package cn.edu.neu.vmmigeval.cloud.entity;

import cn.edu.neu.vmmigeval.cloud.policy.CloudletAllocation;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yfwz100 on 16/2/25.
 */
public class DataCenterBroker {

    public List<Vm> vms;

    /**
     * 没结束的
     */
    public List<Cloudlet> cloudlets;

    /**
     * 结束的
     */
    public List<Cloudlet> finishedCloudlets = new ArrayList<Cloudlet>();

    public CloudletAllocation cloudletAllocation = new CloudletAllocation();

    public void updateVmsProcessing(int clock) {

        if (vms != null && vms.size() != 0) {

            for (Vm vm : vms) {

                int currentCpu = 0;
                int currentRam = 0;
                int currentBw = 0;
                int currentDisk = 0;

                if (vm != null && vm.getCloudlets() != null && vm.getCloudlets().size() != 0) {

                    /**
                     * 该周期vm上的各个cloudlet的资源的随机分配
                     */
                    for (Cloudlet cl : vm.getCloudlets()) {

				/*	//是否已经结束，结束的要删除
					if(cl.getStatus()==1){
						vm.getCloudlets().remove(cl);
						continue;
					}*/
                        //计算vm的资源利用情况
                        int cloudCpu = cl.getCpuUtilizationModel().getUtilization(vm.getTotalCpu());
                        int cloudRam = cl.getRamUtilizationModel().getUtilization(vm.getTotalRam());
                        int cloudBw = cl.getBwUtilizationModel().getUtilization(vm.getTotalBw());
                        int cloudDisk = cl.getDiskUtilizationModel().getUtilization(vm.getTotalDisk());

                        cl.setCpu(cloudCpu);
                        cl.setRam(cloudRam);
                        cl.setBw(cloudBw);
                        cl.setDisk(cloudDisk);

                        currentCpu += cloudCpu;
                        currentRam += cloudRam;
                        currentBw += cloudBw;
                        currentDisk += cloudDisk;
                    }
                    /**
                     * 该周期vm上的各个cloudlet的资源的固定分配，即不能超过该vm上的总的资源情况
                     */
                    updateCloudlets(vm, currentCpu, currentRam, currentBw, currentDisk);
                    /**
                     * 该周期vm上各个cloudlet的执行情况
                     */

                    if (vm != null && vm.getCloudlets() != null && vm.getCloudlets().size() != 0) {
                        //for(Cloudlet cl : vm.getCloudlets()) {
                        for (int i = 0; i < vm.getCloudlets().size(); i++) {
                            Cloudlet cl = vm.getCloudlets().get(i);
                            //执行完成了
                            if (cl.getCloudletFinished() + cl.getCpu() >= cl.getCloudletLength()) {
                                cl.setFinishTime(clock);
                                cl.setStatus(1);
                                finishedCloudlets.add(cl);
                                vm.getCloudlets().remove(cl);
                                //System.out.println("cloudlet size is :"+vm.getCloudlets().size());

                            } else {
                                cl.setCloudletFinished(cl.getCloudletFinished() + cl.getCpu());
                            }
                        }
                        /**
                         * 该周期vm上的资源情况
                         */
                        currentCpu = 0;
                        currentRam = 0;
                        currentBw = 0;
                        currentDisk = 0;
                        for (Cloudlet cl : vm.getCloudlets()) {

						/*	//是否已经结束，结束的要删除
							if(cl.getStatus()==1){
								vm.getCloudlets().remove(cl);
								continue;
							}*/
                            //计算vm的资源利用情况
                            currentCpu += cl.getCpu();
                            currentRam += cl.getRam();
                            currentBw += cl.getBw();
                            currentDisk += cl.getDisk();
                        }
                        vm.setCurrentCpu(currentCpu);
                        vm.setCurrentRam(currentRam);
                        vm.setCurrentBw(currentBw);
                        vm.setCurrentDisk(currentDisk);
                    } else {

                        vm.setCurrentCpu(0);
                        vm.setCurrentRam(0);
                        vm.setCurrentBw(0);
                        vm.setCurrentDisk(0);

                    }

                    List<Double> uh = vm.getUtilizationHistory();
                    if (uh.size() >= 15) {
                        uh.remove(0);
                    }
                    uh.add((double) vm.getCurrentCpu() / vm.getTotalCpu());
                    vm.setUtilizationHistory(uh);


                }
            }
        }
    }

    public void updateCloudlets(Vm vm, int currentCpu, int currentRam, int currentBw, int currentDisk) {

        if (vm.getTotalCpu() < currentCpu) {
            int extra = currentCpu - vm.getTotalCpu();
            int reduce = extra / vm.getCloudlets().size() + 2;
            for (Cloudlet cl : vm.getCloudlets()) {
                if (cl.getCpu() - reduce <= 0) {
                    cl.setCpu(0);
                } else {
                    cl.setCpu(cl.getCpu() - reduce);
                }
                //cl.setCpu(cl.getCpu()-reduce);
                //System.out.println("cpus is :"+cl.getCpu());

            }
        }
        if (vm.getTotalRam() < currentRam) {
            int extra = currentRam - vm.getTotalRam();
            int reduce = extra / vm.getCloudlets().size() + 1;
            for (Cloudlet cl : vm.getCloudlets()) {
                if (cl.getRam() - reduce <= 0) {
                    cl.setRam(0);
                } else {
                    cl.setRam(cl.getRam() - reduce);
                }
                //cl.setRam(cl.getRam()-reduce);
            }
        }
        if (vm.getTotalBw() < currentBw) {
            int extra = currentBw - vm.getTotalBw();
            int reduce = extra / vm.getCloudlets().size() + 1;
            for (Cloudlet cl : vm.getCloudlets()) {
                if (cl.getBw() - reduce <= 0) {
                    cl.setBw(0);
                } else {
                    cl.setBw(cl.getBw() - reduce);
                }
                //cl.setBw(cl.getBw()-reduce);
            }
        }
        if (vm.getTotalDisk() < currentDisk) {
            int extra = currentDisk - vm.getTotalDisk();
            int reduce = extra / vm.getCloudlets().size() + 1;
            for (Cloudlet cl : vm.getCloudlets()) {
                if (cl.getDisk() - reduce <= 0) {
                    cl.setDisk(0);
                } else {
                    cl.setDisk(cl.getDisk() - reduce);
                }
                //cl.setDisk(cl.getDisk()-reduce);
            }
        }
    }

    public List<Vm> getVms() {
        return vms;
    }

    public void setVms(List<Vm> vms) {
        this.vms = vms;
    }

    public List<Cloudlet> getCloudlets() {
        return cloudlets;
    }

    public void setCloudlets(List<Cloudlet> cloudlets) {
        this.cloudlets = cloudlets;
    }

    public CloudletAllocation getCloudletAllocation() {
        return cloudletAllocation;
    }

    public void setCloudletAllocation(CloudletAllocation cloudletAllocation) {
        this.cloudletAllocation = cloudletAllocation;
    }

    public List<Cloudlet> getFinishedCloudlets() {
        return finishedCloudlets;
    }

    public void setFinishedCloudlets(List<Cloudlet> finishedCloudlets) {
        this.finishedCloudlets = finishedCloudlets;
    }


}
